﻿<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ZoomAndPanSample"
    xmlns:ZoomAndPan="clr-namespace:ZoomAndPan;assembly=ZoomAndPan"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="ZoomAndPanSample.MainWindow"
    Title="Main Window" 
    Height="600" 
    Width="800"
    Loaded="MainWindow_Loaded"
    >
    <Window.Resources>

        <!-- UI commands. -->
        <RoutedUICommand x:Key="Commands.ZoomOut" />
        <RoutedUICommand x:Key="Commands.ZoomIn" />
        <RoutedUICommand x:Key="Commands.JumpBackToPrevZoom" />
        <RoutedUICommand x:Key="Commands.Fill" />
        <RoutedUICommand x:Key="Commands.OneHundredPercent" />

        <!-- 
        This converts from a scale value to a percentage value.
        It is used to convert the value of 'ContentScale' to the percentage zoom level that is displayed in the UI.
        -->
        <local:ScaleToPercentConverter 
            x:Key="scaleToPercentConverter" 
            />

        <!-- 
        Converts a color value to a brush.
        -->
        <local:ColorToBrushConverter 
            x:Key="colorToBrushConverter"
            />

        <!--
        Defines the UI for an instance of RectangleData.
        -->
        <DataTemplate 
            DataType="{x:Type local:RectangleData}"
            >
            <Rectangle
                Width="{Binding Width}"
                Height="{Binding Height}"
                Fill="{Binding Color, Converter={StaticResource colorToBrushConverter}}"
                Cursor="Hand"
                MouseDown="Rectangle_MouseDown"
                MouseUp="Rectangle_MouseUp"
                MouseMove="Rectangle_MouseMove"
                />
        </DataTemplate>

        <!-- 
        Override the style of the ListBox to remove the ScrollViewer.
        All we want is ListBox logic but based on a Canvas.
        -->
        <Style x:Key="noScrollViewerListBoxStyle" TargetType="{x:Type ListBox}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBox}">
                        <Canvas 
        					Background="{TemplateBinding Background}"
        					IsItemsHost="True" 
                            />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!-- 
        Override the style of each ListBoxItem to bind Canvas.Left, Canvas.Top and IsSelected.
        -->
        <Style 
            x:Key="listBoxItemStyle" 
            TargetType="{x:Type ListBoxItem}"
            >
            <Setter 
        		Property="Canvas.Left" 
        		Value="{Binding X}" 
                />
            <Setter 
        		Property="Canvas.Top" 
        		Value="{Binding Y}" 
                />
            <Setter 
        		Property="IsSelected" 
        		Value="{Binding IsSelected}" 
                />

            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <!--
                        This border is used for indicating selection.
                        Normally it is transparent, when the item is selected the border is set to blue.
                        -->
                        <Border 
        					x:Name="Border"
        					BorderThickness="1"
        					Padding="2"
                            >
                            <ContentPresenter />
                        </Border>
                        <ControlTemplate.Triggers>
                            <!--
                            When the ListBoxItem is selected draw a simple blue border around it.
                            -->
                            <Trigger Property="IsSelected" Value="true">
                                <Setter 
        							TargetName="Border" 
        							Property="BorderBrush"
        							Value="Blue"
                                    />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    </Window.Resources>

    <Window.InputBindings>

        <!--
        Bind keys to commands.
        -->
        <KeyBinding
			Key="Minus"
			Command="{StaticResource Commands.ZoomOut}"
			/>
        <KeyBinding
			Key="Plus"
			Command="{StaticResource Commands.ZoomIn}"
			/>
        <KeyBinding
			Key="Backspace"
			Command="{StaticResource Commands.JumpBackToPrevZoom}"
			/>

    </Window.InputBindings>

    <Window.CommandBindings>

        <!--
        Bind commands to event handlers.
        -->
        <CommandBinding 
            Command="{StaticResource Commands.ZoomOut}" 
            Executed="ZoomOut_Executed" 
            />
        <CommandBinding 
            Command="{StaticResource Commands.ZoomIn}" 
            Executed="ZoomIn_Executed" 
            />
        <CommandBinding 
            Command="{StaticResource Commands.JumpBackToPrevZoom}" 
            Executed="JumpBackToPrevZoom_Executed" 
            CanExecute="JumpBackToPrevZoom_CanExecuted"
            />
        <CommandBinding 
            Command="{StaticResource Commands.Fill}" 
            Executed="Fill_Executed" 
            />
        <CommandBinding 
            Command="{StaticResource Commands.OneHundredPercent}" 
            Executed="OneHundredPercent_Executed" 
            />

    </Window.CommandBindings>

    <DockPanel>

        <!-- 
        Grid placed below the zoom and pan control that contains the zoom slider, zoom label and
        some button.
        -->
        <Grid
			Margin="5,5,5,5"
			DockPanel.Dock="Bottom" d:IsHidden="True"
            >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <!-- empty space -->
                <ColumnDefinition Width="40" />
                <!-- the fill button -->
                <ColumnDefinition Width="5" />
                <!-- spacer -->
                <ColumnDefinition Width="40" />
                <!-- the 100% button -->
                <ColumnDefinition Width="5" />
                <!-- spacer -->
                <ColumnDefinition Width="25" />
                <!-- the zoom percentage label -->
                <ColumnDefinition Width="15" />
                <!-- the % symbol -->
                <ColumnDefinition Width="5" />
                <!-- spacer -->
                <ColumnDefinition Width="20" />
                <!-- the zoom out button -->
                <ColumnDefinition Width="5" />
                <!-- spacer -->
                <ColumnDefinition Width="120" />
                <!-- the zoom slider -->
                <ColumnDefinition Width="5" />
                <!-- spacer -->
                <ColumnDefinition Width="20" />
                <!-- the zoom in button -->
                <ColumnDefinition Width="10" />
                <!-- spacer -->
                <ColumnDefinition Width="Auto" />
                <!-- resize grip -->
                <!-- spacer -->
            </Grid.ColumnDefinitions>

            <!-- 
            The fill button.  Causes the content to be scaled so that it fits in the viewport.
            -->
            <Button
				Grid.Column="1"
				Command="{StaticResource Commands.Fill}"
                Content="Fill"
                />
            <!-- 
            The 100% button.  Causes the content to be scaled to 100 percent.
            -->
            <Button
				Grid.Column="3"
				Command="{StaticResource Commands.OneHundredPercent}"
                Content="100%"
                />

            <!--
            This is the label that shows what the current zoom level
            is while zooming in and out.
            -->
            <TextBlock
				Grid.Column="5"
				VerticalAlignment="Center"
				HorizontalAlignment="Right"
				Text="{Binding ContentScale, Converter={StaticResource scaleToPercentConverter}, ElementName=zoomAndPanControl}"
                />

            <TextBlock
				Grid.Column="6"
				VerticalAlignment="Center"
				Text="%"
                />

            <!-- Button to zoom out. -->
            <Button
				Grid.Column="8"
				Command="{StaticResource Commands.ZoomOut}"
                Content="-"
                />

            <!-- Slider to change the current zoom level. -->
            <Slider
				Grid.Column="10"
				Minimum="10" 
				LargeChange="20" 
				TickFrequency="10" 
				Maximum="200" 
				SmallChange="10" 
				TickPlacement="TopLeft"
				Value="{Binding ContentScale, Converter={StaticResource scaleToPercentConverter}, ElementName=zoomAndPanControl}"
                />

            <!--
            Button to zoom in.
            -->
            <Button
				Grid.Column="12"
				Command="{StaticResource Commands.ZoomIn}"
                Content="+"
                />

            <!-- Stick a resize grip in the bottom right corner of the window. -->
            <ResizeGrip
				Grid.Column="14"
                />

        </Grid>

        <!--
        This is the control that handles zooming and panning.
        -->
        <ZoomAndPan:ZoomAndPanControl
			x:Name="zoomAndPanControl"
			ContentScale="{Binding ContentScale, Mode=TwoWay, Source={x:Static local:DataModel.Instance}}"
			ContentOffsetX="{Binding ContentOffsetX, Mode=TwoWay, Source={x:Static local:DataModel.Instance}}"
			ContentOffsetY="{Binding ContentOffsetY, Mode=TwoWay, Source={x:Static local:DataModel.Instance}}"
			ContentViewportWidth="{Binding ContentViewportWidth, Mode=OneWayToSource, Source={x:Static local:DataModel.Instance}}"
			ContentViewportHeight="{Binding ContentViewportHeight, Mode=OneWayToSource, Source={x:Static local:DataModel.Instance}}"
			Background="LightGray"
			MouseDown="zoomAndPanControl_MouseDown"
			MouseUp="zoomAndPanControl_MouseUp"
			MouseMove="zoomAndPanControl_MouseMove"
			MouseWheel="zoomAndPanControl_MouseWheel"
			MouseDoubleClick="zoomAndPanControl_MouseDoubleClick"
            >

            <!-- 
            This is the content that is displayed.
            -->
            <Grid
				Width="{Binding ContentWidth, Source={x:Static local:DataModel.Instance}}"
				Height="{Binding ContentHeight, Source={x:Static local:DataModel.Instance}}"
                >
                <!--
            	This ListBox is the main part of the content that is displayed.
                The list box contains instances of RectangleData, the DataTemplate for RectangleData is in
                the UserControl.Resources section of this file.
                -->
                <ListBox
					x:Name="content"
					ItemsSource="{Binding Rectangles, Source={x:Static local:DataModel.Instance}}"
					Style="{StaticResource noScrollViewerListBoxStyle}"
					ItemContainerStyle="{StaticResource listBoxItemStyle}" Background="{x:Null}"
                    />

                <!--
                This Canvas and Border are used as a very simple way to render a drag rectangle that the user
                uses to specify an area to zoom in on.
                -->
                <Canvas
					x:Name="dragZoomCanvas"
					Visibility="Collapsed"
                    >
                    <Border 
						x:Name="dragZoomBorder"
						BorderBrush="Black"
						BorderThickness="1"
						Background="Silver"
						CornerRadius="1"
						Opacity="0"
                        />
                </Canvas>
            </Grid>
        </ZoomAndPan:ZoomAndPanControl>
    </DockPanel>
</Window>
